﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace FloodFill
{
    public class Scanner
    {
        public FloodFiller FloodResult{ get; set; }

        public LinkedList<Node> listEntryPoint;
        public List<Shape> ListShape;
        public Shape MainIsland;

        public Scanner(FloodFiller floodResult) {

            this.FloodResult = floodResult;

            //clono la lista per preservare i valori del floodfill
            this.listEntryPoint = new LinkedList<Node>(
                (from Node n in floodResult.ListEntryPoint
                 select n).ToList<Node>());

            ListShape = new List<Shape>();
            Scan();
        }

        private void Scan()
        {
            int cont = 0;
            while( listEntryPoint.Count > 0 ){
                Node n = listEntryPoint.First.Value;
                listEntryPoint.RemoveFirst();

                if (FloodResult.IsOutOfBounds(n.x, n.z)) continue;

                List<Vector3> listVertex = new List<Vector3>();
                
                Elaborate(listVertex, n);
                
                if ( listVertex.Count > 5)
                    ListShape.Add( new Shape( listVertex ));
                
                cont += listVertex.Count;
            }

            if (ListShape != null && ListShape.Count > 0 ){
                MainIsland = ListShape.OrderByDescending(s => s.Vertex).First<Shape>();
                MainIsland.IsMainIsland = true;
                ListShape.Remove(MainIsland);
            }
            
        }

        private void Elaborate(List<Vector3> listVertex , Node n)
        {
            //floodResult.correctionValue
            listVertex.Add( new Vector3( n.x, n.Value , n.z) );
            FloodResult.MatrixEntryPoint[n.x, n.z] = null;
            ConnectedNode(listVertex, n);
        }

        private void ConnectedNode(List<Vector3> listVertex , Node n)
        {
            int row;
            int col; 

            //top
            row = n.x + 1;    col = n.z;
            ConnectedNode(listVertex, row, col);

            //top right
            row = n.x + 1;    col = n.z + 1;
            ConnectedNode(listVertex, row, col);
            
            //right
            row = n.x;        col = n.z + 1;
            ConnectedNode(listVertex, row, col);
            
            //bottom right
            row = n.x - 1;      col = n.z + 1;
            ConnectedNode(listVertex, row, col);
            
            //bottom
            row = n.x - 1;    col = n.z;
            ConnectedNode(listVertex, row, col);
            
            //bottom left
            row = n.x - 1;    col = n.z - 1;
            ConnectedNode(listVertex, row, col);
            
            //left
            row = n.x;        col = n.z - 1;
            ConnectedNode(listVertex, row, col);
            
            //top left
            row = n.x + 1;    col = n.z - 1;
            ConnectedNode(listVertex, row, col);

        }

        private void ConnectedNode(List<Vector3> listVertex , int row , int col) {
            Node newEntryPoint = GetEntryPoint(row, col);
            if (newEntryPoint != null) {
                Elaborate(listVertex, newEntryPoint);
            }
        }

        private Node GetEntryPoint(int x , int z)
        {
            if (FloodResult.IsOutOfBounds(x, z))            return null;
            if (FloodResult.MatrixEntryPoint[x, z] == null) return null;
            if (FloodResult.MatrixEntryPoint[x, z].CountEntryPoint == 0) return null;
            
            return FloodResult.MatrixEntryPoint[x, z];
        }

        public int rowCount {
            get {
                return this.FloodResult.rowCount;
            }
        }

        public int colCount {
            get {
                return this.FloodResult.colCount;
            }
        }
    }
}
